<?php

declare(strict_types=1);

namespace App\Common\Service;

use App\CustHub\Mapper\ChCorpMapper;
use App\System\Mapper\SystemAppMapper;
use App\System\Model\SystemApp;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Codec\Packer\JsonPacker;
use Hyperf\Contract\PackerInterface;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Guzzle\CoroutineHandler;

class QwNotifyService
{
    protected Client $client;

    protected PackerInterface $packer;

    #[Inject]
    protected SystemAppMapper $systemAppMapper;

    public function __construct()
    {
        $handler = null;
        if (Coroutine::inCoroutine()) {
            $handler = new CoroutineHandler();
        }

        $this->client = new Client([
            'timeout' => 3,
            'handler' => $handler,
        ]);
        $this->packer = new JsonPacker();
    }


    public function pushQwWorkMessage(array $params): void
    {
        $corpId = $params['ToUserName'];
        $corpInfo = container()->get(ChCorpMapper::class)->findByAuthCorpId($corpId);
        if(empty($corpInfo)){
            return;
        }

        $systemApp = $this->systemAppMapper->findByUid($corpInfo->main_uid);
        if(empty($systemApp) || $systemApp->notify_switch != 1){
            return;
        }

        $uri = $systemApp->notify_url;

        $signData = $this->generateSignature($params,$systemApp->app_secret);
        $params = array_merge($params,$signData);

        try {
            $response = $this->client->post($uri, [
                'json' => $params
            ]);
            $responseData = $this->packer->unpack((string) $response->getBody());
            if (!empty($responseData) && $responseData['code'] == 1) {
                logger()->info('推送消息成功');
            } else {
                logger()->info('推送消息失败', ['response' => $responseData]);
            }
        } catch (GuzzleException $e) {
            logger()->error('推送消息异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }


    /**
     * 生成签名
     *
     * @param array  $params   请求参数
     * @param string $secret   签名密钥
     * @param int    $expires  签名有效期（秒）
     * @return array           签名及相关数据
     */
    public function generateSignature(array $params, string $secret, int $expires = 300): array {
        // 添加时间戳和随机数
        $params['timestamp'] = time();
        $params['expires'] = $expires;

        // 按照键名升序排序参数
        ksort($params);

        // 构造待签名的字符串
        $signString = '';
        foreach ($params as $key => $value) {
            if (is_array($value) || is_object($value)) {
                // 对于数组或对象类型，只拼接键名
                $signString .= $key . '&';
            } elseif (is_null($value) || is_bool($value)) {
                // 对于空值或布尔值，转换为空字符串
                $signString .= $key . '=&';
            } else {
                // 对于其他类型，直接使用字符串形式的值
                $signString .= $key . '=' . $value . '&';
            }
        }
        $signString = rtrim($signString, '&');

        // 使用HMAC-SHA256算法生成签名
        $signature = hash_hmac('sha256', $signString, $secret);

        return [
            'signature' => $signature,
            'timestamp' => $params['timestamp'],
            'expires' => $expires
        ];
    }
}